home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 2: CDPD 1 / Almathera Ten on Ten - Disc 2: CDPD 1.iso / pd / 101-125 / 103 / cref / cref.orig.c < prev    next >
C/C++ Source or Header  |  1995-03-13  |  20KB  |  1,027 lines

  1. /*
  2. **   cref - C cross referencer
  3. **    This program reads its standard input or one or more files
  4. **    and prints the file plus an alphabetic list of word references
  5. **    by line number.
  6. **
  7. **    When run using the `-b' option the program keeps the word
  8. **    list in memory.     Otherwise the program uses a temporary
  9. **    word list file which is run through `sort'.  That way it
  10. **    can cross reference extremely large source files.
  11. **    Unfortunately it makes the program run slower.
  12. **
  13. **    To run:
  14. **        cref [-b] [-q] [-lnnn] [-wnnn] [-hheading] [file ...]
  15. **
  16. **    Options:
  17. **        b    - use sort file rather then memory (for large files)
  18. **        q    - don't print normal input file listing
  19. **        lnnn - set page length to n instead of the default 66.
  20. **        wnnn - set page width to n instead of the default 132.
  21. **        hccc - set page heading to 'ccc' rather than file names
  22. **
  23. **    Mike Edmonds - 5/81
  24. */
  25.  
  26. #include <stdio.h>
  27. #include <ctype.h>
  28. #include <signal.h>
  29. #include <sys/types.h>
  30. #include <sys/stat.h>
  31.  
  32. #define MAXWORD        15    /* maximum chars in word */
  33. #define MAXPAGLINES    9999    /* maximum posible lines in page */
  34. #define MAXLINWIDTH    132    /* maximum posible chars in line */
  35.  
  36. #define igncase(c)    (isupper(c)? tolower(c) : (c))
  37.  
  38. #define FALSE    0
  39. #define TRUE    1
  40.  
  41. #ifdef    DEBUG
  42. #define debug(a,b)    fprintf(stderr,(a),(b))
  43. #else
  44. #define debug(a,b)
  45. #endif
  46.  
  47.  
  48.  
  49. /*
  50.  *  global structures
  51.  */
  52.  
  53. #define LINLIST    struct    _linlist
  54. #define WRDLIST    struct    _wrdlist
  55.  
  56. struct    _linlist {        /* line number list node */
  57.     long     ln_no ;      /* line number */
  58.     LINLIST    *ln_next ;      /* next element pointer (or NULL) */
  59. } ;
  60.  
  61. struct    _wrdlist {        /* word list node */
  62.     char    *wd_wd ;      /* pointer to word */
  63.     char    *wd_lwd ;      /* pointer to word (lower case) */
  64.     LINLIST     wd_ln ;      /* first element of line list */
  65.     WRDLIST    *wd_low ;      /* lower child */
  66.     WRDLIST    *wd_hi ;      /* higher child */
  67. } ;
  68.  
  69.  
  70.  
  71. /*
  72.  *  options
  73.  */
  74.  
  75. char    *Progname ;
  76. int     Bigcref = FALSE ;    /* use sort file rather than memory? (-b) */
  77. int     Quiet = FALSE ;    /* don't print input file listing? (-q) */
  78. int     Maxpaglines = 66 ;    /* maximum lines in page (-l) */
  79. int     Maxlinwidth = 132 ;    /* maximum chars in print line (-w) */
  80.  
  81.  
  82.  
  83. /*
  84.  *  global variables
  85.  */
  86.  
  87. char     Crefhdr[MAXLINWIDTH+1] ;/* report header */
  88. char    *Filename ;        /* name of current input file */
  89. char     Date[30] ;        /* current or last file modify date */
  90. long     Hiline = 1L ;        /* current (and max.) input file line number */
  91. char    *Wordfile ;        /* temp. word file name */
  92. FILE    *Wdfile ;        /* temp. word file ptr */
  93. WRDLIST    *Wdtree = NULL ;    /* ptr to root node of binary word list */
  94.  
  95.  
  96.  
  97. /*
  98.  *  C language reserved keywords (in pseudo random order)
  99.  */
  100. char    *Ckeywords[] = {
  101.     "char",
  102.     "static",
  103.     "break",
  104.     "#define",
  105.     "#if",
  106.     "default",
  107.     "#ifdef",
  108.     "#ifndef",
  109.     "register",
  110.     "void",
  111.     "if",
  112.     "while",
  113.     "#line",
  114.     "union",
  115.     "switch",
  116.     "#else",
  117.     "asm",
  118.     "do",
  119.     "#include",
  120.     "#undef",
  121.     "#endif",
  122.     "long",
  123.     "continue",
  124.     "float",
  125.     "short",
  126.     "typedef",
  127.     "for",
  128.     "struct",
  129.     "case",
  130.     "else",
  131.     "unsigned",
  132.     "int",
  133.     "extern",
  134.     "auto",
  135.     "goto",
  136.     "entry",
  137.     "return",
  138.     "double",
  139.     "sizeof",
  140.     0
  141. } ;
  142.  
  143.  
  144.  
  145. onintr(signo)            /* handle interrupts */
  146. {
  147.     signal(signo, SIG_IGN) ;
  148.     unlink(Wordfile) ;
  149.     exit(EOF) ;
  150. }
  151.  
  152.  
  153.  
  154.  
  155. /*
  156.  *  main - Store C keywords.
  157.  *       Get program options and format heading lines.
  158.  *       Get words from input file (or files) and store in temp file or tree.
  159.  *       Retrieve and print in word sequence.
  160.  */
  161. main(argc, argv)
  162. int     argc ;
  163. char    *argv[] ;
  164. {
  165.     char    *mktemp(), wordfilebuf[BUFSIZ] ;
  166.     register FILE    *filep ;
  167.     char    *getword(), *word ;
  168.     struct     stat    stbuf ;
  169.     long     time() ;
  170.     register cnt ;
  171.     int     files=0 ;
  172.  
  173.     Progname = *argv ;        /* get options */
  174.     getcmd(argc, argv) ;
  175.  
  176.                     /* make unique word file name */
  177.     Wordfile = mktemp("/tmp/crefXXXXXX") ;
  178.  
  179.  
  180.                     /* catch interrupts */
  181.     if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
  182.         signal(SIGHUP, onintr) ;
  183.     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  184.         signal(SIGINT, onintr) ;
  185.     if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
  186.         signal(SIGQUIT, onintr) ;
  187.     if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
  188.         signal(SIGTERM, onintr) ;
  189.  
  190.  
  191.                     /* open word file */
  192.     if ((Wdfile = fopen(Wordfile, "w")) == NULL)
  193.         fatal("can't open temp file `%s'", Wordfile) ;
  194.     setbuf(Wdfile, wordfilebuf) ;
  195.  
  196.  
  197.                     /* store C keywords */
  198.     for (cnt=0 ; Ckeywords[cnt] ; cnt++)
  199.         storword(Ckeywords[cnt], 0L) ;
  200.  
  201.  
  202.                     /* read and store files */
  203.     for (cnt=1 ; cnt < argc ; cnt++)
  204.         if (*argv[cnt] != '-')
  205.         {    files++ ;
  206.             Filename = argv[cnt] ;
  207.             if ((filep = fopen(Filename, "r")) == NULL)
  208.                 fatal("can't open %s", Filename) ;
  209.             fstat(fileno(filep), &stbuf) ;
  210.             mkdate((long)stbuf.st_mtime) ;
  211.             while (word = getword(filep))
  212.                 storword(word, Hiline);
  213.             fclose(filep) ;
  214.         }
  215.  
  216.     if (!files)            /* no files - read stdin */
  217.     {    if (*Crefhdr)
  218.             Filename = Crefhdr ;
  219.         else
  220.             Filename = "stdin" ;
  221.         mkdate(time(0)) ;
  222.         while (word = getword(stdin))
  223.             storword(word, Hiline) ;
  224.     }
  225.  
  226.  
  227.     fclose(Wdfile) ;         /* print cross reference report */
  228.     if (Bigcref)
  229.         bigcref() ;
  230.     else
  231.         cref(Wdtree) ;
  232.  
  233.     unlink(Wordfile) ;
  234.     exit(0) ;
  235. }
  236.  
  237.  
  238.  
  239.  
  240.  
  241.  
  242.  
  243.  
  244. /*
  245.  *  getcmd - get arguments from command line & build page headings
  246.  */
  247. getcmd(argc, argv)
  248. register argc ;
  249. register char    *argv[] ;
  250. {
  251.     register cnt ;
  252.  
  253.     debug("GETCMD(%d", argc) ;
  254.     debug(", %s)\n", argv[0]) ;
  255.  
  256.     *Crefhdr = '\0' ;
  257.                     /* get command options */
  258.     for (cnt=1; cnt < argc; cnt++)
  259.     {    if (*argv[cnt] == '-')
  260.         {    switch(argv[cnt][1])
  261.             {  case 'b':
  262.                 Bigcref = TRUE ;
  263.                 break ;
  264.  
  265.                case 'q':
  266.                 Quiet = TRUE ;
  267.                 break ;
  268.  
  269.                case 'l':
  270.                 Maxpaglines = atoi(&argv[cnt][2]) ;
  271.                 if (Maxpaglines < 4
  272.                  || Maxpaglines > MAXPAGLINES)
  273.                     fatal("size error: %s", argv[cnt]) ;
  274.                 break ;
  275.  
  276.                case 'w':
  277.                 Maxlinwidth = atoi(&argv[cnt][2]) ;
  278.                 if (Maxlinwidth < MAXWORD+12
  279.                  || Maxlinwidth > MAXLINWIDTH)
  280.                     fatal("size error: %s", argv[cnt]) ;
  281.                 break ;
  282.  
  283.                case 'h':
  284.                 strncpy(Crefhdr, &argv[cnt][2], MAXLINWIDTH) ;
  285.                 Crefhdr[MAXLINWIDTH] = '\0' ;
  286.                 break ;
  287.  
  288.                default:
  289.                 fatal("invalid option: %s", argv[cnt]) ;
  290.             }
  291.         }
  292.     }
  293.  
  294.                     /* insert file names in hdr */
  295.     if (!*Crefhdr)
  296.         for (cnt=1; cnt < argc; cnt++)
  297.             if (*argv[cnt] != '-')
  298.                 strjoin(Crefhdr, ' ', argv[cnt], MAXLINWIDTH) ;
  299. }
  300.  
  301.  
  302.  
  303.  
  304.  
  305.  
  306.  
  307. /*
  308.  *  getword - read, print and return next word from file
  309.  */
  310. char *
  311. getword(filep)
  312. FILE    *filep ;
  313. {
  314.     static     char    wordbuf[MAXWORD+1] ;
  315.     register char    *wp = wordbuf ;
  316.     register maxw = sizeof(wordbuf) ;
  317.     register chr ;
  318.     int     inword=0, lastchr=0 ;
  319.     long     slineno ;
  320.  
  321. #define    _listchr(chr)    if (!Quiet) listchr(chr)
  322.  
  323. #define    _rtrnwrd(wp)             \
  324.     {    ungetc(chr, filep) ;    \
  325.         *(wp) = '\0' ;        \
  326.         return wordbuf ;    \
  327.     }
  328.  
  329.     while ((chr = getc(filep)) != EOF)
  330.     {    switch (chr)
  331.         {            /* normal char - add to current word */
  332.            case 'a': case 'b': case 'c': case 'd': case 'e':
  333.            case 'f': case 'g': case 'h': case 'i': case 'j':
  334.            case 'k': case 'l': case 'm': case 'n': case 'o':
  335.            case 'p': case 'q': case 'r': case 's': case 't':
  336.            case 'u': case 'v': case 'w': case 'x': case 'y':
  337.            case 'z':
  338.            case 'A': case 'B': case 'C': case 'D': case 'E':
  339.            case 'F': case 'G': case 'H': case 'I': case 'J':
  340.            case 'K': case 'L': case 'M': case 'N': case 'O':
  341.            case 'P': case 'Q': case 'R': case 'S': case 'T':
  342.            case 'U': case 'V': case 'W': case 'X': case 'Y':
  343.            case 'Z':
  344.            case '_':
  345.             if (maxw-- <= 1)
  346.                 _rtrnwrd(wp) ;
  347.             *wp++ = chr ;
  348.             inword++ ;
  349.             _listchr(chr) ;
  350.             break ;
  351.  
  352.                     /* digit - can't be 1st char in word */
  353.            case '0': case '1': case '2': case '3': case '4':
  354.            case '5': case '6': case '7': case '8': case '9':
  355.             if (inword)
  356.             {    if (maxw-- <= 1)
  357.                     _rtrnwrd(wp) ;
  358.                 *wp++ = chr ;
  359.             }
  360.             _listchr(chr) ;
  361.             break ;
  362.  
  363.                     /* '#' - must be 1st char in word */
  364.            case '#':
  365.             if (inword)
  366.                 _rtrnwrd(wp) ;
  367.             *wp++ = chr ;
  368.             inword++ ;
  369.             _listchr(chr) ;
  370.             break ;
  371.  
  372.                     /* newline - end current word */
  373.            case '\n':
  374.             if (inword)
  375.                 _rtrnwrd(wp) ;
  376.             _listchr(chr) ;
  377.             Hiline++ ;
  378.             break ;
  379.  
  380.                     /* comments - print & bypass */
  381.            case '/':
  382.             if (inword)
  383.                 _rtrnwrd(wp) ;
  384.             _listchr(chr) ;
  385.             slineno = Hiline ;
  386.             if ((chr = getc(filep)) == '*')
  387.             {    _listchr(chr) ;
  388.                 while (chr != EOF)
  389.                 {    chr = getc(filep) ;
  390.                     _listchr(chr) ;
  391.                     if (chr == '\n')
  392.                         Hiline++ ;
  393.                     else if (chr == '*')
  394.                     {    chr = getc(filep) ;
  395.                         _listchr(chr) ;
  396.                         if (chr == '\n')
  397.                             Hiline++ ;
  398.                         else if (chr == '/')
  399.                             break ; ;
  400.                     }
  401.                 }
  402.                 if (chr == EOF)
  403.                     fatal("unterminated comment at %ld in %s", slineno, Filename) ;
  404.             }
  405.             else
  406.                 ungetc(chr, filep) ;
  407.             break ;
  408.  
  409.                     /* words in quotes - print & bypass */
  410.            case '"':
  411.             if (inword)
  412.                 _rtrnwrd(wp) ;
  413.             _listchr(chr) ;
  414.             slineno = Hiline ;
  415.             if (lastchr != '\\')
  416.             {    do
  417.                 {    if (chr == '\\' && lastchr == '\\')
  418.                         lastchr = '\0' ;
  419.                     else
  420.                         lastchr = chr ;
  421.                     if ((chr = getc(filep)) == EOF)
  422.                         fatal("unterminated quote at %ld in %s", slineno, Filename) ;
  423.                     _listchr(chr) ;
  424.                     if (chr == '\n')
  425.                         Hiline++ ;
  426.                 } while (chr != '"' || lastchr == '\\') ;
  427.             }
  428.             break ;
  429.  
  430.                     /* letters in quotes - print & bypass */
  431.            case '\'':
  432.             if (inword)
  433.                 _rtrnwrd(wp) ;
  434.             _listchr(chr) ;
  435.             if (isprint(chr = getc(filep)))
  436.             {    _listchr(chr) ;
  437.                 if (chr == '\\')
  438.                 {    if (!isprint(chr = getc(filep)))
  439.                         goto toofar ;
  440.                     _listchr(chr) ;
  441.                 }
  442.                 if ((chr = getc(filep)) != '\'')
  443.                     goto toofar ;
  444.                 _listchr(chr) ;
  445.             }
  446.             else
  447.                toofar:
  448.                 ungetc(chr, filep) ;
  449.             break ;
  450.  
  451.            default:
  452.             if (inword)
  453.                 _rtrnwrd(wp) ;
  454.             _listchr(chr) ;
  455.             break ;
  456.         }
  457.  
  458.         lastchr = chr ;
  459.     }
  460.  
  461.     if (inword)
  462.         _rtrnwrd(wp) ;
  463.     _listchr(EOF) ;
  464.     return NULL ;
  465. }
  466.  
  467.  
  468.  
  469.  
  470.  
  471.  
  472.  
  473.  
  474. /*
  475.  *  listchr - list the input files one character at a time
  476.  */
  477.  
  478. static    Listpage = 0 ;
  479. static    Listpline = MAXPAGLINES ;
  480.  
  481. listchr(chr)
  482. register chr ;
  483. {
  484.     static    char     linebuf[MAXLINWIDTH*2], *lineptr=linebuf ;
  485.     static    lastchr=0, linecnt=0 ;
  486.  
  487.     if (chr == EOF)            /* EOF - print final line */
  488.     {    *lineptr = '\0' ;
  489.         listline(linebuf) ;
  490.         Listpage = 0 ;
  491.         Listpline = MAXPAGLINES ;
  492.         lineptr = linebuf ;
  493.         linecnt = 0 ;
  494.         return ;
  495.     }
  496.  
  497.     if (lineptr == linebuf)        /* new line - format line number */
  498.     {    ltoc(linebuf, Hiline, 6) ;
  499.         lineptr = linebuf+6 ;
  500.         *lineptr++ = '\t' ;
  501.         linecnt = 8 ;
  502.     }
  503.  
  504. #define    _lineoflo(ctr, newctr)        \
  505.     if ((ctr) >= Maxlinwidth)    \
  506.     {    *lineptr = '\0' ;    \
  507.         listline(linebuf) ;    \
  508.         lineptr = linebuf ;    \
  509.         *lineptr++ = '\t' ;    \
  510.         linecnt = (newctr) ;    \
  511.     }
  512.  
  513.     switch (chr)
  514.     {                /* newline - print last line */
  515.        case '\n':
  516.         if (lastchr != '\f')
  517.         {    *lineptr = '\0' ;
  518.             listline(linebuf) ;
  519.         }
  520.         lineptr = linebuf ;
  521.         linecnt = 0 ;
  522.         break ;
  523.  
  524.                      /* formfeed - print line and end page */
  525.        case '\f':
  526.         if (linecnt != 8)
  527.         {    *lineptr = '\0' ;
  528.             listline(linebuf) ;
  529.         }
  530.         Listpline = MAXPAGLINES ;
  531.         lineptr = linebuf ;
  532.         linecnt = 0 ;
  533.         break ;
  534.  
  535.                     /* tab - skip to next tab stop */
  536.        case '\t':
  537.         linecnt += 8 ;
  538.         linecnt &= ~07 ;
  539.         _lineoflo(linecnt, 16) ;
  540.         *lineptr++ = chr ;
  541.         break ;
  542.  
  543.                     /* backspace - print, but don't count */
  544.        case '\b':
  545.         *lineptr++ = chr ;
  546.         break ;
  547.  
  548.                     /* ctl-char - print as "^x" */
  549.              case 001: case 002: case 003:
  550.        case 004: case 005: case 006: case 007:
  551.                      case 013:
  552.                  case 015: case 016: case 017:
  553.        case 020: case 021: case 022: case 023:
  554.        case 024: case 025: case 026: case 027:
  555.        case 030: case 031: case 032: case 033:
  556.        case 034: case 035: case 036: case 037:
  557.         _lineoflo(linecnt+=2, 10) ;
  558.         *lineptr++ = '^' ;
  559.         *lineptr++ = ('A'-1) + chr ;
  560.         break ;
  561.  
  562.                     /* printable chars */
  563.        case 'A': case 'B': case 'C': case 'D': case 'E':
  564.        case 'F': case 'G': case 'H': case 'I': case 'J':
  565.        case 'K': case 'L': case 'M': case 'N': case 'O':
  566.        case 'P': case 'Q': case 'R': case 'S': case 'T':
  567.        case 'U': case 'V': case 'W': case 'X': case 'Y':
  568.        case 'Z':
  569.        case 'a': case 'b': case 'c': case 'd': case 'e':
  570.        case 'f': case 'g': case 'h': case 'i': case 'j':
  571.        case 'k': case 'l': case 'm': case 'n': case 'o':
  572.        case 'p': case 'q': case 'r': case 's': case 't':
  573.        case 'u': case 'v': case 'w': case 'x': case 'y':
  574.        case 'z':
  575.        case '0': case '1': case '2': case '3': case '4':
  576.        case '5': case '6': case '7': case '8': case '9':
  577.        case ' ':
  578.        case '!': case '"': case '#': case '$': case '%':
  579.        case '&': case '(': case ')': case '*': case '+':
  580.        case ',': case '-': case '.': case '/': case ':':
  581.        case ';': case '<': case '=': case '>': case '?':
  582.        case '@': case '[': case ']': case '^': case '_':
  583.        case '`': case '{': case '|': case '}': case '~':
  584.        case '\'': case '\\':
  585.         _lineoflo(++linecnt, 9) ;
  586.         *lineptr++ = chr ;
  587.         break ;
  588.  
  589.        default:
  590.         if (isprint(chr))
  591.         {    _lineoflo(++linecnt, 9) ;
  592.             *lineptr++ = chr ;
  593.         }
  594.  
  595.         else        /* non-ascii chars - print as "\nnn" */
  596.         {    _lineoflo(linecnt+=4, 12) ;
  597.             *lineptr++ = '\\' ;
  598.             *lineptr++ = '0' + ((chr & 0300) >> 6) ;
  599.             *lineptr++ = '0' + ((chr & 070) >> 3) ;
  600.             *lineptr++ = '0' + (chr & 07) ;
  601.         }
  602.         break ;
  603.     }
  604.     lastchr = chr ;
  605. }
  606.  
  607.             /* print a completed line from the input file */
  608. listline(line)
  609. register char    *line ;
  610. {
  611.     if (*line)
  612.     {    if (++Listpline >= (Maxpaglines-8))
  613.         {    putchar('\f') ;
  614.             printf("\n%s %s  Page %d\n\n",
  615.                 Date, Filename, ++Listpage) ;
  616.             Listpline = 0 ;
  617.         }
  618.         puts(line) ;
  619.     }
  620. }
  621.  
  622.  
  623.  
  624.  
  625.  
  626.  
  627.  
  628.  
  629.  
  630. /*
  631.  *  storword - store word and line # in binary word tree or word file
  632.  */
  633.  
  634. #define _writeword(word, lword, lineno) \
  635.         fprintf(Wdfile, "%s\t%s\t%06ld\n", (lword), (word), (lineno))
  636.  
  637. storword(word, lineno)
  638. register char    *word ;
  639. long     lineno ;
  640. {
  641.     char     lword[MAXWORD+1] ;
  642.     register char    *cp1, *cp2 ;
  643.     WRDLIST    *addword() ;
  644.  
  645.                     /* convert word to lower case */
  646.     for (cp1=word, cp2=lword ; *cp2++ = igncase(*cp1) ; cp1++)
  647.         ;
  648.  
  649.                     /* store words and lineno */
  650.     if (Bigcref)
  651.         _writeword(word, lword, lineno) ;
  652.     else
  653.         Wdtree = addword(Wdtree, word, lword, lineno) ;
  654. }
  655.  
  656.  
  657.  
  658. /*
  659.  *  addword - add word and line# to in-core word list
  660.  */
  661. WRDLIST *
  662. addword(wdp, word, lword, lineno)
  663. register WRDLIST *wdp ;
  664. char    *word, *lword ;
  665. long     lineno ;
  666. {
  667.     char    *malloc() ;
  668.     int     comp ;
  669.  
  670.                     /* insert new word into list */
  671.     if (wdp == NULL)
  672.     {    register wordlen = strlen(word) + 1 ;
  673.  
  674.         wdp = (WRDLIST *)malloc((wordlen * 2) + sizeof(WRDLIST)) ;
  675.         if (wdp == NULL)
  676.             goto nomemory ;
  677.  
  678.         wdp->wd_wd  = (char *)wdp + sizeof(WRDLIST) ;
  679.         wdp->wd_lwd = wdp->wd_wd + wordlen ;
  680.         strcpy(wdp->wd_wd,  word) ;
  681.         strcpy(wdp->wd_lwd, lword) ;
  682.  
  683.         wdp->wd_hi = wdp->wd_low = NULL ;
  684.         wdp->wd_ln.ln_no = lineno ;
  685.         wdp->wd_ln.ln_next = NULL ;
  686.     }
  687.  
  688.                     /* word matched in list? */
  689.     else if (((comp = strcmp(lword, wdp->wd_lwd)) == 0)
  690.           && ((comp = strcmp(word,  wdp->wd_wd))  == 0))
  691.     {    register LINLIST *lnp, **lnpp ;
  692.  
  693.         if (wdp->wd_ln.ln_no)
  694.         {              /* add line# to linked list */
  695.             lnp = &wdp->wd_ln ;
  696.             do
  697.             {    if (lineno == lnp->ln_no)
  698.                     return wdp ;
  699.                 lnpp = &lnp->ln_next ;
  700.             } while ((lnp = *lnpp) != NULL) ;
  701.  
  702.             *lnpp = (LINLIST *)malloc(sizeof(LINLIST)) ;
  703.             if ((lnp = *lnpp) == NULL)
  704.                 goto nomemory ;
  705.             lnp->ln_no = lineno ;
  706.             lnp->ln_next = NULL ;
  707.         }
  708.     }
  709.  
  710.     else if (comp < 0)        /* search for word in children */
  711.         wdp->wd_low = addword(wdp->wd_low, word, lword, lineno) ;
  712.     else
  713.         wdp->wd_hi = addword(wdp->wd_hi, word, lword, lineno) ;
  714.  
  715.     return wdp ;
  716.  
  717.  
  718.                     /* not enough memory - convert to -b */
  719. nomemory:
  720.     error("not enough memory for in-core word list - using -b option") ;
  721.  
  722.     _writeword(word, lword, lineno) ; /* write current word in file */
  723.     dumptree(Wdtree) ;          /* dump tree into file */
  724.     Bigcref = TRUE ;
  725.     return wdp ;
  726. }
  727.  
  728.  
  729.  
  730.  
  731.  
  732.  
  733. /*
  734.  *  dumptree - ran out of memory for in-core word list - dump tree into file
  735.  */
  736. dumptree(wdp)
  737. register WRDLIST *wdp ;
  738. {
  739.     register LINLIST *lnp ;
  740.  
  741.     if (wdp != NULL)
  742.     {    dumptree(wdp->wd_low) ;    /* dump children */
  743.         dumptree(wdp->wd_hi) ;
  744.  
  745.                     /* dump parent */
  746.         _writeword(wdp->wd_wd, wdp->wd_lwd, wdp->wd_ln.ln_no) ;
  747.         for (lnp=wdp->wd_ln.ln_next ; lnp != NULL ; lnp=lnp->ln_next)
  748.         {    _writeword(wdp->wd_wd, wdp->wd_lwd, lnp->ln_no) ;
  749.             free((char *)lnp) ;
  750.         }
  751.         free((char *)wdp) ;
  752.     }
  753. }
  754.  
  755.  
  756.  
  757.  
  758.  
  759.  
  760.  
  761.  
  762.  
  763. /*
  764.  *  cref - print cross reference report from internal word list
  765.  */
  766. #define MAXLNOS 2000        /* maximum line nos. for a word */
  767. long    Linenos[MAXLNOS] ;    /* list of line numbers for a word */
  768.  
  769. cref(wdtree)
  770. register WRDLIST *wdtree ;
  771. {
  772.     creftree(wdtree) ;
  773.     putchar('\f') ;
  774. }
  775.  
  776. creftree(wdp)            /* recursively print word tree nodes */
  777. register WRDLIST *wdp ;
  778. {
  779.     register LINLIST *lnp ;
  780.     register nos ;
  781.  
  782.     if (wdp != NULL)
  783.     {    creftree(wdp->wd_low) ;    /* print lower children */
  784.  
  785.         nos = 0 ;
  786.         if (Linenos[0] = wdp->wd_ln.ln_no)
  787.         {    lnp = &wdp->wd_ln ;
  788.             while ((lnp = lnp->ln_next) != NULL)
  789.                 if (nos < (MAXLNOS-2))
  790.                     Linenos[++nos] = lnp->ln_no ;
  791.             printword(wdp->wd_wd, nos) ;
  792.         }
  793.  
  794.         creftree(wdp->wd_hi) ;    /* print higher children */
  795.     }
  796. }
  797.  
  798.  
  799.  
  800.  
  801.  
  802.  
  803.  
  804. /*
  805.  *  bigcref - print cross reference report from word file
  806.  */
  807. bigcref()
  808. {
  809.     char     oldword[MAXWORD+1], word[MAXWORD+1], lword[MAXWORD+1] ;
  810.     long     lineno ;
  811.     register args, nos ;
  812.     int     pid, child, status ;
  813.  
  814.                     /* sort word file */
  815.     if ((child = fork()) == 0)
  816.     {    execl("/usr/bin/sort", "sort", "-o", Wordfile, Wordfile, 0);
  817.         fatal("can't execute /bin/sort") ;
  818.     }
  819.     while (((pid = wait(&status)) != child) && (pid >= 0))
  820.         ;
  821.     if ((pid < 0) || status)
  822.         fatal("can't sort temp file `%s'", Wordfile) ;
  823.  
  824.  
  825.                     /* re-open word file */
  826.     if ((Wdfile = fopen(Wordfile, "r")) == NULL)
  827.         fatal("can't open temp file `%s'", Wordfile) ;
  828.  
  829. #define _readword()    fscanf(Wdfile, "%s %s %ld", lword, word, &lineno)
  830.  
  831.     args = _readword() ;
  832.     while (args == 3)
  833.     {    strcpy(oldword, word) ;
  834.         if (Linenos[0] = lineno)
  835.         {    nos = 0 ;
  836.             while ((args = _readword()) == 3)
  837.             {    if (strcmp(word, oldword))
  838.                     break ;
  839.                 if ((Linenos[nos] != lineno)
  840.                  && (nos < (MAXLNOS-2)))
  841.                     Linenos[++nos] = lineno ;
  842.             }
  843.             printword(oldword, nos) ;
  844.         }
  845.         else
  846.             while ((args = _readword()) == 3)
  847.                 if (strcmp(word, oldword))
  848.                     break ;
  849.     }
  850.  
  851.     putchar('\f') ;
  852.     fclose(Wdfile) ;
  853. }
  854.  
  855.  
  856.  
  857.  
  858.  
  859.  
  860.  
  861.  
  862. /*
  863.  *  printword - print a word and all its line number references
  864.  */
  865. printword(word, nos)
  866. char    *word ;
  867. register nos ;
  868. {
  869.     static    firstime=TRUE, linecnt, maxlnos, lnosize ;
  870.     register cnt ;
  871.  
  872.     if (firstime)
  873.     {    firstime = FALSE ;
  874.         linecnt = Maxpaglines ;
  875.         for (lnosize=1 ; Hiline ; lnosize++)
  876.             Hiline /= 10L ;
  877.         maxlnos = (Maxlinwidth - (MAXWORD+7)) / lnosize ;
  878.     }
  879.  
  880.     if (linecnt >= (Maxpaglines - 8))
  881.     {    printheads() ;
  882.         linecnt = 5 ;
  883.     }
  884.  
  885.     printf("%-15s%5d  ", word, ++nos) ;
  886.     Linenos[nos] = 0 ;
  887.  
  888.     for (nos=0, cnt=0 ; Linenos[nos] ; nos++)
  889.     {    if (++cnt > maxlnos)
  890.         {    cnt = 1 ;
  891.             if (linecnt++ >= (Maxpaglines - 2))
  892.             {    printheads() ;
  893.                 linecnt = 5 ;
  894.                 printf("%-15s(cont) ", word);
  895.             }
  896.             else
  897.                 printf("\n%22s", " ") ;
  898.         }
  899.         printf("%*ld", lnosize, Linenos[nos]) ;
  900.     }
  901.     putchar('\n') ;
  902.  
  903.     linecnt++ ;
  904. }
  905.  
  906.  
  907.  
  908. /*
  909.  *  printheads - print page headings
  910.  */
  911. printheads()
  912. {
  913.     static    page=0 ;
  914.     long    time() ;
  915.  
  916.     if (!page)
  917.         mkdate(time(0)) ;
  918.  
  919.     putchar('\f') ;
  920.     printf("\nCREF  %s %.*s  Page %d\n\n",
  921.         Date, (Maxlinwidth-36), Crefhdr, ++page) ;
  922.     printf("word             refs    line numbers\n\n") ;
  923. }
  924.  
  925.  
  926.  
  927.  
  928.  
  929.  
  930.  
  931.  
  932. /*
  933.  *  ltoc - store ASCII equivalent of long value in given field
  934.  */
  935. ltoc(fld, lval, len)
  936. register char    *fld ;
  937. register long    lval ;
  938. register len ;
  939. {
  940.     fld += len ;
  941.     while (len-->0)
  942.         if (lval)
  943.         {    *--fld = '0' + (lval%10L) ;
  944.             lval /= 10L ;
  945.         }
  946.         else
  947.             *--fld = ' ' ;
  948. }
  949.  
  950.  
  951.  
  952. /*
  953.  *  mkdate - build time/date for use in heading lines
  954.  */
  955. mkdate(atime)
  956. long    atime ;
  957. {
  958.     long    mtime ;
  959.     char    *cp, *ctime() ;
  960.  
  961.     debug("MKDATE(%ld)\n", atime) ;
  962.  
  963.     mtime = atime ;
  964.     cp = ctime(&mtime) ;
  965.     *(cp+24) = ' ' ;        /* clear newline */
  966.     strcpy(cp+16, cp+19) ;        /* shift over seconds */
  967.     strcpy(Date, cp+4) ;
  968. }
  969.  
  970.  
  971.  
  972. /*
  973.  *  strjoin - join "str1" to "str2" (separated by "sep")
  974.  *    Truncate if necessary to "max" chars.
  975.  */
  976. strjoin(str1, sep, str2, max)
  977. register char    *str1, *str2;
  978. char    sep ;
  979. register max ;
  980. {
  981.     if (*str2)
  982.     {    if (*str1)
  983.         {    while (*str1++)
  984.                 if (--max <= 0)
  985.                     goto oflo ;
  986.             max--, str1-- ;
  987.             *str1++ = sep ;
  988.         }
  989.         while (*str1++ = *str2++)
  990.             if (--max <= 0)
  991.                 goto oflo ;
  992.     }
  993.     return ;
  994.  
  995. oflo:
  996.     *--str1 = '\0' ;
  997.     return ;
  998. }
  999.  
  1000.  
  1001.  
  1002.  
  1003.  
  1004.  
  1005.  
  1006. /*
  1007.  *  error - print standard error msg
  1008.  */
  1009. error(ptrn, data1, data2)
  1010. register char    *ptrn, *data1, *data2 ;
  1011. {
  1012.     fprintf(stderr, "%s: ", Progname) ;
  1013.     fprintf(stderr, ptrn, data1, data2) ;
  1014.     putc('\n', stderr) ;
  1015. }
  1016.  
  1017.  
  1018. /*
  1019.  *  fatal - print standard error msg and halt process
  1020.  */
  1021. fatal(ptrn, data1, data2)
  1022. register char    *ptrn, *data1, *data2 ;
  1023. {
  1024.     error(ptrn, data1, data2) ;
  1025.     kill(getpid(), SIGTERM) ;
  1026. }
  1027.